function Table(blockID,serverDownText,tableDim) {
    Block.call(this,blockID,serverDownText);

    var dim = typeof tableDim === 'object'?tableDim:[];
    var rangeCheckEnabled = dim?true:false;
    if(typeof dim[0] === 'number') {
        dim[0] = [dim[0],dim[1]];
        dim[1] = dim[0];
    }
    var ind = {'headerRow':0,'headerElem':0,'bodyRow':1,'bodyElem':1};

    this.checkRange = function(elem,row,col) {
        var r1 = rangeCheckEnabled?rangeCheckEnabled:true;
        var r2 = typeof row === 'undefined'?true:row >= 0 && row < dim[ind[elem]][0];
        var r3 = typeof col === 'undefined'?true:col >= 0 && col < dim[ind[elem]][1];
        return r1 && r2 && r3;
    }
    this.updateElem = function(
                elem,
                row,col,
                url,
                historyAction,
                onComplete,
                onFailure,
                evalScripts
                ) {
                if (this.checkRange(elem,row,col)){
                    var wName = blockID+elem+parseInt(row)+parseInt(col);
                    this.setGenericParams(onComplete, onFailure, evalScripts);
                    this.makeUpdate(wName,url,{method: "post",
                                        parameters: "data="+[row,col].toJSONString(),
                                        onComplete: this.onCompleteFunc,
                                        onFailure: this.onFailureFunc,
                                        evalScripts: this.jsEval});
                }
                else if (rangeCheckEnabled)
                    alert('Table '+blockID+': out of range check failed');
    }
    this.updateBodyElem = function(row,col,url,historyAction,onComplete,onFailure,evalScripts) {
        this.updateElem('bodyElem',row,col,url,historyAction,onComplete,onFailure,evalScripts);
    }
    this.updateHeaderElem = function(row,col,url,historyAction,onComplete,onFailure,evalScripts) {
        this.updateElem('headerElem',row,col,url,historyAction,onComplete,onFailure,evalScripts);
    }
    this.updateRow = function(
                row,
                rowNum,
                url,
                historyAction,
                onComplete,
                onFailure,
                evalScripts
                ) {
                if (this.checkRange(row,rowNum)) {
                    var wName = blockID+row+parseInt(rowNum);
                    this.setGenericParams(onComplete, onFailure, evalScripts, historyAction);
                    this.makeUpdate(wName,url,
                                    {method: "post",
                                    parameters: "data="+rowNum.toJSONString(),
                                    onComplete: this.onCompleteFunc,
                                    onFailure: this.onFailureFunc,
                                    evalScripts: this.jsEval});
                }
                else if (rangeCheckEnabled)
                    alert('Table '+blockID+': out of range check failed');
    }
    this.updateBodyRow = function(rowNum,url,historyAction,onComplete,onFailure,evalScripts) {
        this.updateRow('bodyRow',rowNum,url,historyAction,onComplete,onFailure,evalScripts);
    }
    this.updateHeaderRow = function(rowNum,url,historyAction,onComplete,onFailure,evalScripts) {
        this.updateRow('headerRow',rowNum,url,historyAction,onComplete,onFailure,evalScripts);
    }
    this.updateElemList = function(
                elem,
                rowColPairs,
                url,
                historyAction,
                onComplete,
                onFailure,
                evalScripts
                ) {
                var wNames = new Array();
                for(pairInd=0;pairInd<rowColPairs.length;pairInd++) {
                    var row = rowColPairs[pairInd][0];
                    var col = rowColPairs[pairInd][1];
                    if (this.checkRange(elem,row,col))
                        wNames[pairInd] = blockID+elem+parseInt(row)+parseInt(col);
                    else if (rangeCheckEnabled) {
                        alert('Table '+blockID+': out of range check failed');
                        return;
                    }
                }
                var onCompleteFunc = function(request) {
                    var response = request.responseText.parseJSON();
                    var backup = new Array();
                    for(pairInd=0;pairInd<rowColPairs.length;pairInd++) {
                        backup.push($(wNames[pairInd]).innerHTML);
                        $(wNames[pairInd]).innerHTML=response[pairInd];
                    }
                    return new HistoryItem( historyAction,
                                        new HistoryData(wNames, response),
                                        new HistoryData(wNames, backup));
                }
                this.setGenericParams(onCompleteFunc, onFailure, evalScripts);
                this.makeRequest(url, {method: "post",
                                  parameters: "data="+rowColPairs.toJSONString(),
                                  onComplete: this.onCompleteFunc,
                                  onFailure: this.onFailureFunc,
                                  evalScripts: this.jsEval});
    }
    this.updateBodyElemList = function(rowColPairs,url,historyAction,onComplete,onFailure,evalScripts) {
        this.updateElemList('bodyElem',rowColPairs,url,historyAction,onComplete,onFailure,evalScripts);
    }
    this.updateHeaderElemList = function(rowColPairs,url,historyAction,onComplete,onFailure,evalScripts) {
        this.updateElemList('headerElem',rowColPairs,url,historyAction,onComplete,onFailure,evalScripts);
    }
}
